// 证明：每个线程的栈都是独立的
// 主线程可以获取次线程的变量，尝试次线程可以获取次线程的变量
// 使用线程局部存储

#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
#define NUM 3

int global_var = 0; //全局变量
__thread int TLS_val = 0;//TLS全局变量

class ThreadData
{
public:
    ThreadData(string name, int num)
        : _name(name), _CreateOrder(num)
    {
    }

public:
    pthread_t _tid;
    string _name;
    int _CreateOrder; // 创建线程的次序
    int* _StackData = nullptr; // 线程栈上的数据
};

// 转16进制
string ToHexString(int num)
{
    std::stringstream ss;
    ss << std::hex << num;
    return ss.str();
}

//创建返回字符串
string ToStringForRet(const ThreadData* _td)
{
    string ret = "tid:"+ ToHexString(pthread_self()) + " "
    +"thread name:"+_td->_name+" "
    +"\n"
    +"thread stack data:" + ToHexString(*_td->_StackData) +" "
    +"thread stack data address:" + ToHexString((size_t)_td->_StackData)+" "
    +"\n"
    +"TLS var:" + to_string(TLS_val)+" "
    +"TLS var address:" + ToHexString((size_t)&TLS_val)+" "
    +"\n"
    +"thread create order:" + to_string(_td->_CreateOrder)+" "
    +"\n"
    +"global var:" + to_string(global_var)+" "
    +"global var address:" + ToHexString((size_t)&global_var)+" "
    +"\n\n";
    return ret;
}

void printTLS(ThreadData* td)
{
    cout<<"Thread name"<<td->_name<<":"<<
        "TLS_val:"<<TLS_val<<" "<<ToHexString((size_t)&TLS_val)<<endl;
}

void *ThreadExec(void *agrv)
{
    int loacl_var = 0;
    ThreadData *td = (ThreadData *)agrv;
    int co = 0;
    // 根据不同的线程创建顺序，对局部变量进行不同的修改
    if (td->_CreateOrder == 0)
    {
        co += 1;
    }
    else if (td->_CreateOrder == 1)
    {
        co += 2;
    }
    else if (td->_CreateOrder == 2)
    {
        co += 3;
    }

    // 测试TLS的变量是否会被覆盖
    TLS_val = 100;
    while(true)
    {
        printTLS(td);
        sleep(1);
    }
    // 线程栈上的数据被开辟在堆上的结构体字段指针管理
    td->_StackData = &co; 

    // 修改全局变量
    global_var++;
    // 修改局部变量
    loacl_var++;

    string* ret = new string(ToStringForRet(td));
    delete td;
    return (void *)ret;
}



// 创建十个线程
int main()
{
    int fd = open("ThreadData.txt", O_TRUNC | O_CREAT | O_WRONLY, 0664);
    vector<pthread_t> tids; // 用于记录线程的id
    for (int i = 0; i < NUM; i++)
    {
        pthread_t tid;
        ThreadData *td = new ThreadData("Thread" + to_string(i), i);
        pthread_create(&tid, nullptr, ThreadExec, td);
        tids.push_back(tid);
        td->_tid = tids[i];
    }

    // 测试TLS的变量是否会被覆盖
    TLS_val = 101;
    while(true)
    {
        cout<<"Thread name"<<"main"<<":"
        "TLS_val:"<<TLS_val<<" "<<ToHexString((size_t)&TLS_val)<<endl;
        sleep(1);
    }
    for (int i = 0; i < NUM; i++)
    {
        void *ret;
        pthread_join(tids[i], &ret);
        string *data = (string *)ret;
        write(fd, data->c_str(), data->size());
        delete data;
    }
    std::cout<<"global var:"<<global_var<<std::endl;
    close(fd);
    return 0;
}